#include "stdafx.h"
#include "dibapi.h"
#include "jpegapi.h"
#include <afxpriv.h>
#include "IJL.h"


#ifndef DIBIMAGE_NO_JPEG
      

// byte offsets
#define BO_BLUE     0
#define BO_GREEN    1
#define BO_RED      2



          
HDIB ReadJPEGFile(CFile& file)
{
	//For correct operation of the T2A macro, see MFC Tech Note 59
	USES_CONVERSION;

  //Keep a local copy of the filename for usage with the IJL functions.
  //Note that since IJL does not support Unicode we must perform the 
  //Unicode to Ascii conversion
  char lpszAsciiFileName[MAX_PATH];
  TCHAR pszFileName[_MAX_PATH];
  _tcscpy(pszFileName, file.GetFilePath());
  strcpy(lpszAsciiFileName, T2A(pszFileName));
  ASSERT(strlen(lpszAsciiFileName));

  JPEG_CORE_PROPERTIES image;
  ZeroMemory(&image, sizeof(JPEG_CORE_PROPERTIES));
  BYTE* pImageData;
  DWORD imageSize;

  TRY
  {
    //Init the IJL
    if (ijlInit(&image) != IJL_OK)
    {
	    TRACE(_T("Cannot initialize Intel JPEG library!\n"));
	    AfxThrowUserException();
    }

    //Read in the Jpeg file parameters
    image.JPGFile = (LPTSTR) lpszAsciiFileName; //LPTSTR cast is required since the IJL
                                                //header files are prototyped to use a 
                                                //LPTSTR even through Intel have currently
                                                //only released Ascii versions of IJL as of v1.0

    if (ijlRead(&image, IJL_JFILE_READPARAMS) != IJL_OK)
    {
	    TRACE(_T("Cannot read JPEG file header from %s file!\n"), image.JPGFile);
	    AfxThrowUserException();
    }
  
    //Allocate memory for the image
    int nChannels = 3;
    imageSize = image.JPGWidth*image.JPGHeight*nChannels;
    pImageData = new BYTE[imageSize];
    if (pImageData == NULL)
    {
	    TRACE(_T("Cannot allocate memory for image\n"));
	    AfxThrowMemoryException();
    }

    //Call the IJL to load the Jpeg from file
    image.DIBWidth    = image.JPGWidth;
    image.DIBHeight   = image.JPGHeight;
    image.DIBChannels = nChannels;
    image.DIBBytes    = pImageData;
    if (ijlRead(&image, IJL_JFILE_READWHOLEIMAGE) != IJL_OK)
    {
	    TRACE(_T("Cannot read image pImageData from %s file!\n"), image.JPGFile);
	    delete [] pImageData;
	    AfxThrowUserException();
    }

    //Finished with IJL
    if (ijlFree(&image) != IJL_OK) 
	    TRACE(_T("Cannot free Intel(R) JPEG library!"));
  }
  CATCH_ALL(e)
  {
	  ijlFree(&image);
    TRACE(_T("Error opening JPEG file!\n"));
		return NULL;
  }
  END_CATCH_ALL

  // initializing incapsulated image with correct values
  SIZE imageDims;
  imageDims.cx = image.JPGWidth;
  imageDims.cy = image.JPGHeight;

  BITMAPINFO bmi;
  BITMAPINFOHEADER& bih = bmi.bmiHeader;
  ZeroMemory(&bih, sizeof(BITMAPINFOHEADER));
  bih.biSize = sizeof(BITMAPINFOHEADER);
  bih.biWidth = imageDims.cx;
  bih.biHeight = imageDims.cy;
  bih.biCompression = BI_RGB;
  bih.biPlanes = 1;
  bih.biBitCount = 24;

  //Allocate a buffer to use for the transfer to DIB format
  imageSize = imageDims.cy*(imageDims.cx*3+((4-((imageDims.cx*3)&3))&3));
  BYTE* pBmp = new BYTE[imageSize];
  if (pBmp == NULL) 
    return NULL;

  //Copy the DIB bits from the user buffer into the DIB
  int lagDelta = ((4-((imageDims.cx*3)&3))&3);
  int lag = (imageDims.cy - 1)*lagDelta;
  for (int j=0; j<imageDims.cy; j++)
  {
    for( int i = 0; i<imageDims.cx; i++ )
    {
      int bidx = j*imageDims.cx*3 + i*3;
      int bidxbmp = (imageDims.cy - j - 1)*imageDims.cx*3 + i*3;

      pBmp[bidxbmp+lag+BO_RED]   = pImageData[bidx+BO_RED];
      pBmp[bidxbmp+lag+BO_GREEN] = pImageData[bidx+BO_GREEN];
      pBmp[bidxbmp+lag+BO_BLUE]  = pImageData[bidx+BO_BLUE];
    }
    lag -= lagDelta;
  }

  //Delete the memory used to load the jpeg prior to transfering to the DIB
	delete [] pImageData;

  // Allocate memory for DIB
  HDIB hDIB = (HDIB) ::GlobalAlloc(GHND, bih.biSize + imageSize);
  if (hDIB == 0)
  {
		delete [] pBmp;
		return NULL;
  }
  LPSTR pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  if (pDIB == 0)
  {
	  delete [] pBmp;
    return NULL;
  }

  CopyMemory(pDIB, &bmi.bmiHeader, bih.biSize);
  CopyMemory(pDIB + bih.biSize, pBmp, imageSize);
  delete [] pBmp;

  ::GlobalUnlock((HGLOBAL) hDIB);
  return hDIB;
}

/*************************************************************************
*
* SaveJPEGFile()
*
* Saves the specified DIB as a JPEG into the specified CFile.  The CFile
* is opened and closed by the caller.
*
* Parameters:
*
* HDIB hDib - Handle to the dib to save
*
* CFile& file - open CFile used to save as JPEG
*
* Return value: TRUE if successful, else FALSE or CFileException
*
*************************************************************************/

BOOL SaveJPEGFile(HDIB hDib, CFile& file, DWORD dwQuality)
{
	//For correct operation of the T2A macro, see MFC Tech Note 59
	USES_CONVERSION;

  BOOL bSuccess = TRUE;
  BYTE* pBmp = NULL;
  BYTE* pImageData = NULL;

  //No bitmap, then cannot save
  if (hDib == NULL)
    return FALSE;

  //Keep a local copy of the filename for usage with the IJL functions.
  //Note that since IJL does not support Unicode we must perform the 
  //Unicode to Ascii conversion
  char lpszAsciiFileName[MAX_PATH];
  TCHAR pszFileName[_MAX_PATH];
  _tcscpy(pszFileName, file.GetFilePath());
  strcpy(lpszAsciiFileName, T2A(pszFileName));
  ASSERT(strlen(lpszAsciiFileName));

  //Close the file if it was open
  file.Close();

  // Get a pointer to the DIB memory, the first of which contains
  // a BITMAPINFO structure
  LPBITMAPINFOHEADER lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
  if (lpBI == NULL)
    return FALSE;
   
  if (!IS_WIN30_DIB(lpBI))
  {
    AfxMessageBox(_T("Only Windows 3.0 DIB images can be saved as JPEG!\n"));
    ::GlobalUnlock((HGLOBAL) hDib);
    return FALSE;  // It's an other-style DIB (save not supported)
  }

  if (lpBI->biBitCount != 24)
  {
    AfxMessageBox(_T("Only 16 million colors (24 bit) images can be saved as JPEG!\n"));
    ::GlobalUnlock((HGLOBAL) hDib);
    return FALSE;
  }

  if (lpBI->biCompression != BI_RGB)
  {
    AfxMessageBox(_T("RLE-compressed images can't be saved as JPEG!\n"));
    ::GlobalUnlock((HGLOBAL) hDib);
    return FALSE;
  }

  DWORD dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI);  // Partial Calculation

  // Now calculate the size of the image

  DWORD dwBmBitsSize;  // Size of Bitmap Bits only
  // It's not RLE, so size is Width (DWORD aligned) * Height
  dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
  dwDIBSize += dwBmBitsSize;

  // Now, since we have calculated the correct size, why don't we
  // fill in the biSizeImage field (this will fix any .BMP files which
  // have this field incorrect).
  lpBI->biSizeImage = dwBmBitsSize;

  JPEG_CORE_PROPERTIES image;
  ZeroMemory(&image, sizeof(JPEG_CORE_PROPERTIES));
		
  TRY
  {
    //Init the IJL
    if (ijlInit(&image) != IJL_OK)
    {
      AfxMessageBox(_T("Can't initialize Intel(R) JPEG library!\n"));
      AfxThrowUserException();
    }

    image.jquality = dwQuality; // [0...100], best is 100
											          // LIB's default is 75, our default is 100
    SIZE imageDims;
    imageDims.cx = lpBI->biWidth;
    imageDims.cy = lpBI->biHeight;

    // Setup DIB
    image.DIBWidth = imageDims.cx;
    image.DIBHeight = imageDims.cy;

    // Setup JPEG
    image.JPGFile = (LPTSTR) lpszAsciiFileName; //LPTSTR cast is required since the IJL
                                                //header files are prototyped to use a 
                                                //LPTSTR even through Intel have currently
                                                //only released Ascii versions of IJL as of v1.0
    image.JPGWidth = imageDims.cx;
    image.JPGHeight = imageDims.cy;

    pImageData = (BYTE*)lpBI + lpBI->biSize;

    //Allocate some memory to save the Dib bits into 
    pBmp = new BYTE[dwDIBSize];
    if (pBmp == NULL) 
    {
	    ::GlobalUnlock((HGLOBAL) hDib);
	    return NULL;
    }

    //Copy the Dib bits into the buffer we just allocated
    int lag = 0;
    int lagDelta = ((4-((imageDims.cx*3)&3))&3);
	int j=0;
    for (; j<imageDims.cy; j++)
    {
      for (int i=0; i<imageDims.cx; i++)
      {
	      int bidx = j*imageDims.cx*3 + i*3;
	      pBmp[bidx + BO_RED]	  = pImageData[bidx + BO_RED + lag];
	      pBmp[bidx + BO_GREEN]	= pImageData[bidx + BO_GREEN + lag];
	      pBmp[bidx + BO_BLUE]	= pImageData[bidx + BO_BLUE + lag];
      }
      lag += lagDelta;
    }

    ::GlobalUnlock((HGLOBAL)hDib);

    pImageData = new BYTE[dwDIBSize - lpBI->biSize];
    if (pImageData == NULL) 
    {
	    delete [] pBmp;
	    return NULL;
    }

    CopyMemory(pImageData, pBmp, dwDIBSize - lpBI->biSize);

    //upside-down, right?
    for (j=0; j<imageDims.cy; j++)
    {
      for (int i=0; i<imageDims.cx; i++)
      {
        int bidxbmp = (imageDims.cy - j - 1)*imageDims.cx*3 + i*3;
        int bidx = j*imageDims.cx*3 + i*3;

        pBmp[bidxbmp]	    = pImageData[bidx];
        pBmp[bidxbmp + 1]	= pImageData[bidx + 1];
        pBmp[bidxbmp + 2]	= pImageData[bidx + 2];
      }
    }

    image.DIBBytes = pBmp; //now it's OK for IJL!

    delete [] pImageData;

    //Call the IJL to write the Jpeg to file
    if (ijlWrite(&image, IJL_JFILE_WRITEWHOLEIMAGE) != IJL_OK)
    {
      TRACE(_T("Can't write jpeg image\n") );
      AfxThrowUserException();
    }

    //Finished with IJL  
    if (ijlFree(&image) != IJL_OK)
      TRACE(_T("Can't free Intel(R) JPEG library!\n"));
  }
  CATCH_ALL(e)
  {
    bSuccess = FALSE;
    ijlFree(&image);
    TRACE(_T("Error storing JPEG file!\n"));
  }
  END_CATCH_ALL

  delete [] pBmp;
  return bSuccess;
}


#endif //DIBIMAGE_NO_JPEG


